<!--下拉框选择表格数据组件，一个下拉框点击后弹出表格并选择数据-->
<template>
  <a-form-item :label="label" :title="getText()">
    <a-input
        readOnly
        ref="input"
        v-decorator="vDecorator"
        style="padding-right:80px;"
        :style="getStyle"
        :placeholder="!isDisabled?cplaceholder:''"
        :class="{'c-form-disabled':isDisabled,'c-form-input':true}"
        @mouseover="onMouseMoveOver"
        @mouseout="onMouseMoveOut"
        @mousemove="onMouseMoveMove"
    ></a-input>
    <!-- 排序表格,鼠标悬停时展示已选择的数据 -->
    <div
        ref="cSortTable"
        class="c-sort-table"
        :style="'width:'+tablePosition.width+'px;top:'+tablePosition.top+'px;left:'+tablePosition.left+'px;'+'padding-top:1px;'"
        v-show="sortable&&!isDisabled&&mouseIn&&dataSource.length>0"
        @mouseenter="(e)=>onMouseMoveOver(e,true)"
        @mouseleave="(e)=>onMouseMoveOut(e,true)"
    >
      <AntTable
          ref="mainTable"
          :tableMoveable="!isDisabled"
          :autoLoad="false"
          :pageable="false"
          :tableSort="false"
          :tableShowSetting="false"
          :tableHeight="tableHeight"
          :tableTitle="sortTableTitle"
          :tableMoveInfoFields="textField"
          @rowDrag="rowDrag"
      >
        <template v-slot:action="info">
          <AntTableButtonGroup>
            <a @click="deleteRow(info.row)">删除</a>
          </AntTableButtonGroup>
        </template>
      </AntTable>
    </div>
    <!-- 图标+后置按钮 -->
    <div class="input-div">
      <i
          v-show="mouseIn&&dataSource.length>0&&!isDisabled"
          aria-label="图标: close-circle"
          class="input-close anticon anticon-close-circle ant-select-clear-icon"
          @mouseover="onMouseMoveOver"
          @mouseout="onMouseMoveOut"
          @click="deleteAll"
      >
        <svg
            viewBox="64 64 896 896"
            data-icon="close-circle"
            width="1em"
            height="1em"
            fill="currentColor"
            aria-hidden="true"
            focusable="false"
        >
          <path
              d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
          />
        </svg>
      </i>
      <a-button @click="showModal" :disabled="isDisabled" type="primary"
                :class="{'input-button':true,'c-button-disabled':isDisabled}"
      >
        <a-icon v-if="icon&&!loading" :type="icon"/>
        <a-icon v-if="loading" type="loading"/>
        {{ buttonTitle }}
      </a-button>
    </div>
    <!-- 鼠标点击选择按钮时的表格弹窗 -->
    <AntModalTable
        ref="modalTable"
        :modalTitle="modalTitle"
        :url="url"
        :rowKey="valueField"
        :params="params"
        :tableTop="tableTop"
        :selectable="selectable"
        :tableTitle="tableTitle"
        :leftTableTop="leftTableTop"
        :leftColSpan="leftColSpan"
        :leftCondition="leftCondition"
        :leftConditionFunc="leftConditionFunc"
        :tableWidth="tableWidth"
        @selectData="selectData"
        @beforeMainSearchCallback="beforeMainSearchCallback"
    >
      <!--表格查询条件插槽-->
      <slot></slot>
      <template slot="tableTop">
        <slot name="tableTop"></slot>
      </template>
      <template slot="leftCondition">
        <slot name="leftCondition"></slot>
      </template>
    </AntModalTable>
  </a-form-item>
</template>

<script>
import './css/form.less'
import { mixin } from './js/form.js'
// 表格每行默认高度
const tableRowDefaultHeight = 40
export default {
  name: 'AntFormSelectTable',
  mixins: [mixin],
  props: {
    /**
     * 是否禁用
     */
    disabled: {
      type: Boolean,
      default: false
    },
    /**
     * 是否由form表单自动布局
     */
    autoLayoutByForm: {
      type: Boolean,
      default: true
    },
    /**
     * 组件输入框标题
     */
    label: {
      type: String,
      default: ''
    },
    /**
     * 输入提示
     */
    placeholder: {
      type: String,
      default: ''
    },
    /**
     * 绑定字段 ['phone' ,{ rules: [{ required: true},{validator:function(rule, value, callback)] }],自定义验证方法时callback回调函数必须在方法中调用，
     * 失败返回错误提示callback("xxx")，成功返回callback()
     * 字段值多个逗号隔开
     */
    vDecorator: {
      type: Array,
      default: () => []
    },
    /**
     * 选择按钮文字
     */
    buttonTitle: {
      type: String,
      default: '选择'
    },
    /**
     * 选择按钮icon图标
     */
    icon: {
      type: String,
      default: null
    },
    /**
     * 弹出选择表格的标题
     */
    modalTitle: {
      type: String,
      default: '弹出框'
    },
    /**
     * 必填，下拉组件绑定字段的值所对应的表格数据字段，在初始化时会自动已这个字段为查询条件查询表格已选择的数据
     * 表格数据主键字段，必须唯一，必须在tableTitle中存在字段
     */
    valueField: {
      type: String,
      default: null
    },
    /**
     * 必填，下拉组件绑定字段的值所对应的表格数据中需要显示到输入框中的字段,在回显已选择的数据时能回显到输入框中，多个逗号隔开
     */
    textField: {
      type: String,
      default: 'text'
    },
    /**
     * 非必填，已选择数据的查询条件字段，在表单回显vDecorator有值的情况，会调用initFormUrl将这个自多作为查询条件查询之前已选择的值，不给默认使用vDecorator
     */
    checkedField: {
      type: String,
      default: null
    },
    /**
     * 表格数据接口url
     */
    url: {
      type: String,
      default: ''
    },
    /**
     * 初始化加载表格已选择数据时的url，如果不传，则使用表格url
     */
    initFormUrl: {
      type: String,
      default: null
    },
    /**
     * 必填，表格标题信息
     */
    tableTitle: {
      type: Array,
      default: () => []
    },
    /**
     * 表格选择弹出框打开之前校验函数，返回false则不打卡，返回json则加入查询条件中
     */
    checkModalForm: {
      type: Function,
      default: () => {
        return {}
      }
    },
    /**
     * 表格数据是否可多选框
     */
    selectable: {
      type: Boolean,
      default: false
    },
    /**
     * 是否展示已选择的数据表格，并可对已选择的数据排序
     */
    sortable: {
      type: Boolean,
      default: false
    },
    /**
     * 展示已选择的数据表格的表格标题，sortable为true时必须传入
     */
    sortTableTitle: {
      type: Array,
      default: () => []
    },
    /**
     * 弹出表格，选择弹出框时，是否自动加载数据
     */
    notAutoLoad: {
      type: Boolean,
      default: false
    },
    /**
     * 弹出表格，是否显示左侧条件框区域
     */
    leftCondition: {
      type: Boolean,
      default: false
    },
    /**
     * 弹出表格，左侧查询条件区域顶部标题是否显示，依赖leftCondition必须是true
     */
    leftTableTop: {
      show: false,
      title: '',
      style: ''
    },
    /**
     * 弹出表格，左侧条件框列所占比例，占满为24
     */
    leftColSpan: {
      type: Number,
      default: 6
    },
    /**
     * 弹出表格，获取左侧条件栏自定义参数，若return null/false，则阻止mainSearch()后续查询操作，返回对象会将其值放入mainSearch查询条件中
     */
    leftConditionFunc: {
      type: Function,
      default: () => {
        return {}
      }
    },
    /**
     * 弹出表格，头部区域自定义编辑
     */
    tableTop: {
      type: Boolean,
      default: false
    },
    /**
     * 弹出表格，表格宽度
     */
    tableWidth: {
      type: String,
      default: ''
    },
    /**
     * css样式，优先级最高
     */
    cstyle: {
      type: String,
      default: ''
    },
    /**
     * 非自动布局的宽度，优先级最低
     */
    defaultWidth: {
      type: Number,
      default: 240
    }
  },
  data() {
    return {
      //是否禁用和输入提示，由AntForm组件调用
      cdisabled: false,
      cplaceholder: this.placeholder ? this.placeholder : '请选择' + this.label,
      dataSource: [],
      // 自定义查询条件
      params: {},
      // 鼠标在当前区域内 - 删除按钮显示、表格排序显示
      mouseIn: false,
      // 表格每行默认高度
      tableHeight: tableRowDefaultHeight,
      // 数据加载
      loading: false,
      // 提示信息 相关属性
      messageAttributes: {
        show: false,
        top: 0,
        left: 0
      },
      // 表格位置
      tablePosition: {
        top: 0,
        left: 0,
        width: 0
      }
    }
  },
  computed: {
    key() {
      return this.vDecorator[0]
    },
    /**
     * 获取样式
     */
    getStyle() {
      return { width: (this.percentageLayoutWidth ? this.percentageLayoutWidth : this.defaultWidth) + 'px', ...this.cstyle }
    }
  },
  created() {
  },
  mounted() {
    // 自动加载表格dom
    this.reloadDomOnBody()
    // 自动添加验证为空时的message
    let vDecorator = this.vDecorator
    if (vDecorator.length > 1 && vDecorator[1].rules) {
      let rules = vDecorator[1].rules
      rules.forEach(obj => {
        if (obj.required && !obj.message) {
          obj.message = '请选择' + this.label
        }
      })
    }
  },
  beforeDestroy() {
    // 销毁表格dom
    this.$refs.cSortTable.remove()
  },
  methods: {
    /**
     * 页面挂载初始化，将dom挂载到body上 - 只挂载一次
     */
    reloadDomOnBody() {
      // 页面挂载初始化，将dom挂载到body上 - 只挂载一次
      if (document.body.append) {
        // 在IE11中 document.appendChild会报错: javascript runtime error:HierarchyRequestError
        document.body.append(this.$refs.cSortTable)
      } else {
        document.body.appendChild(this.$refs.cSortTable)
      }
    },
    /**
     * 数据加载，修改时 查询key 赋值
     * @param value
     */
    loadDataByKey(value) {
      let obj = { [this.key]: value }
      if (this.checkedField) {
        obj = { [this.checkedField]: value }
      }
      this.loading = true
      this.$getAction(this.initFormUrl ? this.initFormUrl : this.url, obj).then(res => {
        const data = res.rows
        this.dataSource = data || []
        this.loading = false
      })
    },
    /**
     * 显示弹出框表格
     */
    showModal() {
      const check = this.checkModalForm()
      if (check === false) {
        return
      }
      this.params = { ...check }
      this.$nextTick(() => {
        this.$refs.modalTable.showModal(this.notAutoLoad)
        if (this.dataSource.length > 0) {
          this.$refs.modalTable.setTableCheckBoxByPrimaryKey(this.dataSource.map(el => el[this.valueField]), this.valueField, true)
        }
      })
    },
    /**
     * 弹出框表格查询
     */
    mainSearch() {
      this.$nextTick(() => {
        if (this.$refs.modalTable) {
          this.$refs.modalTable.mainSearch()
        }
      })
    },
    /**
     * 弹出框隐藏
     */
    winCancel() {
      this.$refs.modalTable.winCancel()
    },
    /**
     * 选择数据确定
     * @param dataSource
     */
    selectData(dataSource) {
      this.dataSource = dataSource
      this.$emit('selectData', dataSource)
    },
    /**
     * 获取选择表格数据中的值
     */
    getValue() {
      const keys = this.dataSource.map(el => (this.valueField ? el[this.valueField] : el[this.key]))
      return keys.length > 0 ? keys.join(',') : ''
    },
    /**
     * 获取选择表格数据中的显示值
     */
    getText() {
      return this.dataSource.map(el => el[this.textField]).join('；')
    },
    /**
     * 获取父级form表单
     */
    getParentForm(param) {
      if (param.$refs.aform) {
        return param.$refs.aform.form
      } else {
        return this.getParentForm(param.$parent)
      }
    },
    /**
     * 赋值之前的转换操作,由AntForm组件自动调用
     * 参数：recordPara，转换之前的record
     * 返回值：转换之后的可用于赋值的对象
     */
    beforeSetValue(recordPara) {
      let key = this.vDecorator[0]
      let val = recordPara[key]
      // 抛出主键值，外层加载数据
      if (val) {
        this.loadDataByKey(val)
      }
      return {}
    },
    /**
     * 取值之前的转换操作,由AntForm组件自动调用
     * 参数：recordPara，转换之前的record
     * 返回值：转换之后的对象
     */
    beforeGetValue(recordPara) {
      let record = {}
      let key = this.vDecorator[0]
      record[key] = this.getValue()
      return record
    },
    /**
     * 清空组件值
     */
    resetField() {
      this.dataSource = []
    },
    /**
     * 鼠标移入，展示已选择的表格数据
     * @param e
     * @param hideMessage
     */
    onMouseMoveOver(e, hideMessage) {
      if (!this.mouseIn) {
        // 计算当前表格dom的位置
        const rect = this.$refs.input.$el.getBoundingClientRect()
        this.tablePosition = {
          top: rect.bottom + 4,
          left: rect.left,
          width: rect.width
        }
        this.mouseIn = true
        this.reloadTableHeight(this.$refs.mainTable.getTableData())
      }
      if (hideMessage) {
        this.setMessageAttributes(false, 0, 0)
      }
    },
    /**
     * 鼠标移动
     * @param e
     */
    onMouseMoveMove(e) {
      this.setMessageAttributes(true, e.target.offsetHeight - 5, e.target.offsetLeft + e.offsetX + 10)
    },
    /**
     * 鼠标移出，隐藏已选择的表格数据
     * @param e
     * @param hideMessage
     */
    onMouseMoveOut(e, hideMessage) {
      if (this.mouseIn) {
        // 恢复表格dom
        this.tablePosition = {
          top: 0,
          left: 0
        }
        this.mouseIn = false
      }
      if (hideMessage) {
        this.setMessageAttributes(false, 0, 0)
      }
    },
    /**
     * 删除所有选择数据
     */
    deleteAll() {
      this.dataSource = []
    },
    /**
     * 拖拽行排序移动成功
     */
    rowDrag() {
      this.dataSource = this.$refs.mainTable.getTableData()
    },
    /**
     * 设置提示信息相关属性
     * @param show
     * @param top
     * @param left
     */
    setMessageAttributes(show, top, left) {
      if (this.messageAttributes.show !== show) {
        this.messageAttributes.show = show
      }
      if (top >= 0 && this.messageAttributes.top !== top) {
        this.messageAttributes.top = top
      }
      if (left && this.messageAttributes.left !== left) {
        this.messageAttributes.left = left
      }
    },
    /**
     * 是否重构表格高度
     * @param tableData
     */
    reloadTableHeight(tableData) {
      if (tableData.length <= 10) {
        this.tableHeight = tableData.length * tableRowDefaultHeight
      } else {
        this.tableHeight = 10 * tableRowDefaultHeight
      }
      const rect = this.$refs.input.$el.getBoundingClientRect()
      const maxHeight = document.documentElement.clientHeight - rect.bottom - 60
      if (this.tableHeight > maxHeight) {
        this.tableHeight = maxHeight > 0 ? maxHeight : 0
      }
    },
    /**
     * 表格弹出框加载数据前回调
     * @param modalTableThis
     */
    beforeMainSearchCallback(modalTableThis) {
      this.$emit('beforeMainSearchCallback', modalTableThis)
    },
    /**
     * 删除选择的数据
     * @param row
     */
    deleteRow(row) {
      this.dataSource = this.$refs.mainTable.getTableData().filter(el => el !== row)
    }
  },
  watch: {
    /**
     * 修改dataSource数组后，更新from表单域的值
     */
    dataSource: {
      handler(tableData, oldValue) {
        let str = this.getText()
        const c = this.getParentForm(this.$parent)
        let key = this.vDecorator[0]
        const record = {}
        record[key] = str
        c.setFieldsValue(record)
        // 设置已选数据表格的值
        this.reloadTableHeight(tableData)
        this.$refs.mainTable.setTableData(tableData, tableData.length)
      },
      deep: true
    }
  }
}
</script>

<style lang="less" scoped>
.input-div {
  right: 0px;
  display: flex;
  position: absolute;
  flex-flow: row nowrap;
  justify-content: space-around;

  .input-close {
    top: -27px;
    opacity: 0.4;
    margin-right: 5px;
    position: relative;
  }

  .input-close:hover {
    opacity: 0.7;
    cursor: pointer;
  }

  .input-button {
    top: -36px;
    border-radius: 0 4px 4px 0;
  }
}

.c-sort-table {
  position: absolute;
  z-index: 1000;
  width: 100%;
  margin-top: -4px;
  border: 1px ridge #cfcfcf;
}

.c-message {
  position: absolute;
  border: 1px solid #c0c0c0;
  background-color: #e3e3e3;
  text-align: center;
  line-height: 20px;
  font-size: 12px;
  font-family: 'Microsoft YaHei';
  color: #606266;
  z-index: 100;
  padding: 0 5px;
}

::v-deep .ant-input:hover,
::v-deep .ant-input:focus {
  border-color: @primary-color;
}

.c-button-disabled {
  border-color: #CCCCCC !important;
  background: #f5f5f5 !important;
  color: #1D2129 !important;
}
</style>
